home *** CD-ROM | disk | FTP | other *** search
- /* makeDNS.c -- generate DNS RRs from /etc/hosts
- * Copyright (c) 1991, 1992 Department of Computer Science, University of
- * Edinburgh. Non-commercial use and redistribution is permitted provided this
- * notice remains intact and any modifications are flagged.
- *
- * This software is offered "as is", with no warranty or support whatsoever.
- * Please send comments to gdmr@dcs.ed.ac.uk.
- */
-
- /* Generate a set of DNS RR files from /etc/hosts and some configuration
- * files, under a reasonable set of assumptions. The program expects to
- * be running in the target directory. It reads the file ".configure" in
- * that directory. The file consists of a sequence of "wire" records, one
- * per line, each one listing the network number, netmask, RR file, header
- * file and full domain name for all hosts on that wire. Alternatively,
- * a "domain" record consists of 0.0.0.0 as network number, domain, RR file
- * and header file.
- *
- * The /etc/hosts file is read in, and hosts are added to a 2-way linked list,
- * sorted alphabetically by host name (ordering in the DNS doesn't matter,
- * and this sorting allows the program's assumptions to be implemented).
- * Primary names are held with their corresponding IP address, while aliases
- * have the name of the corresponding primary.
- *
- * Once the hosts file has been read in, the output files are opened and
- * the constant header information is written (with the sequence number
- * properly updated). The hosts list is then scanned in ascending order
- * and the corresponding entries written according to the following
- * heuristics: if a host name has as its leading component one of the
- * preceding hosts then it is assumed to be a second interface on a
- * multi-homed host, and an additional A record is written; and the domain
- * of a host is taken to be that of its first A record, as defined in the
- * corresponding "wire" entry. Finally the program exits with a zero status.
- *
- * Should any errors occur, the program will exit with a non-zero status.
- */
-
- #define HOSTS "/etc/hosts"
- #define CONFIG "Configure"
- #define LOG "Log"
- #define MAXWIRE 63
- #define MAXDOMAIN 5
- #define LINEBUFFER 120
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <pwd.h>
- #include <sys/time.h>
- #include <fcntl.h>
- #include <time.h>
-
- typedef struct _domain {
- char *domainname;
- char *RRfile;
- char *headerfile;
- char *otherZonefile;
- char *MXfile;
- FILE *file;
- FILE *other;
- char *MXdata;
- } domain;
-
- typedef struct _wire {
- long number;
- long netmask;
- char *RRfile;
- char *headerfile;
- char *domainname;
- FILE *file;
- domain *d;
- } wire;
-
- typedef struct _host {
- struct _host *forward;
- struct _host *backward;
- long IP;
- char *name;
- struct _host *primary;
- wire *w;
- } host;
-
- static host *hostlist;
- static wire wireTable[MAXWIRE];
- static domain domainTable[MAXDOMAIN];
- static int domains, wires;
-
- void readconfig();
- void readhosts();
- void printhosts();
- void openfiles();
- void closefiles();
-
- main()
- { readconfig();
- readhosts();
- openfiles();
- printhosts();
- closefiles();
- return 0;
- }
-
- static void addhost(h)
- host *h;
- { host *x;
- if (hostlist == NULL) {
- /* List empty, easy case */
- h->forward = NULL;
- h->backward = NULL;
- hostlist = h;
- return;
- }
- x = hostlist;
- /* Skip to insertion point */
- while (strcmp(x->name, h->name) < 0) {
- if (x->forward) {
- /* More, skip */
- x = x->forward;
- }
- else {
- /* Add at the tail of the list */
- h->forward = NULL;
- h->backward = x;
- x->forward = h;
- return;
- }
- }
- /* Sanity check: duplicate? */
- if (!strcmp(x->name, h->name)) {
- (void) fprintf(stderr, "%s duplicate!\n", h->name);
- return;
- }
- /* Insert before x */
- h->forward = x;
- h->backward = x->backward;
- if (x->backward) x->backward->forward = h; /* Middle */
- else hostlist = h; /* Head */
- x->backward = h;
- }
-
- static long IPconvert(ch)
- char **ch;
- { long N1, N2, N3, N4;
- N1 = strtol(*ch, ch, 10); (*ch)++;
- N2 = strtol(*ch, ch, 10); (*ch)++;
- N3 = strtol(*ch, ch, 10); (*ch)++;
- N4 = strtol(*ch, ch, 10); (*ch)++;
- return (N1 << 24) | (N2 << 16) | (N3 << 8) | N4;
- }
-
- static char *extractname(ch)
- char **ch;
- { char *it;
- char *name;
- int n = 0;
- while (isspace(**ch)) (*ch)++;
- if (**ch == '\0' || **ch == '#') return NULL;
- it = *ch;
- while (!isspace(**ch)) {
- (*ch)++;
- n++;
- }
- **ch = '\0'; (*ch)++;
- name = (char *) malloc(n + 1);
- strcpy(name, it);
- return name;
- }
-
- static wire *findWire(IP)
- long IP;
- { int n;
- wire *w;
- if (IP == 0) return NULL;
- for (n = 0, w = wireTable; n < wires; n++, w++) {
- if ((IP & w->netmask) == w->number) {
- return w;
- }
- }
- return NULL;
- }
-
- static domain *findDomain(name)
- char *name;
- { int n;
- domain *d;
- for (n = 0, d = domainTable; n < domains; n++, d++) {
- if (!strcmp(name, d->domainname)) {
- return d;
- }
- }
- return NULL;
- }
-
- static void readhosts()
- { FILE *hosts;
- host *h, *ph;
- char *ch;
- char buffer[LINEBUFFER];
- long IP;
- char *primary;
- char *alias;
- wire *w;
-
- if ((hosts = fopen(HOSTS, "r")) == NULL) {
- (void) fprintf(stderr, "Failed to open %s\n", HOSTS);
- exit(1);
- }
-
- for (;;) {
- if ((ch = fgets(buffer, LINEBUFFER, hosts)) == NULL) break;
- while (isspace(*ch)) ch++;
- if (*ch == '\0' || *ch == '#') continue;
- IP = IPconvert(&ch);
- if ((w = findWire(IP)) == NULL) continue;
- primary = extractname(&ch);
- ph = (host *) malloc(sizeof(host));
- ph->IP = IP;
- ph->w = w;
- ph->name = primary;
- ph->primary = NULL;
- addhost(ph);
- while (*ch != '\0') {
- alias = extractname(&ch);
- if (alias == NULL) break;
- h = (host *) malloc(sizeof(host));
- h->IP = 0;
- h->w = w;
- h->name = alias;
- h->primary = ph;
- addhost(h);
- }
- }
- (void) fclose(hosts);
- }
-
- static host *findPrincipal(like)
- host *like;
- { host *h;
- int l, n;
-
- h = like->backward;
- l = strlen(like->name);
- while (h) {
- if (*(h->name) != *(like->name)) return NULL;
- n = strlen(h->name);
- if ((n < l) && !isalnum(like->name[n]) &&
- !strncmp(h->name, like->name, n)) {
- return h;
- }
- h = h->backward;
- }
- return NULL;
- }
-
- #define printIP(file, IP) \
- (void) fprintf(file, "%d.%d.%d.%d", \
- (IP >> 24) & 255, (IP >> 16) & 255, (IP >> 8) & 255, IP & 255)
-
- /* printhosts has four cases:
- * 1 IP address, no principal entry -- write the name as it stands, plus
- * the reverse name, again as it stands.
- * 2 IP address plus principal entry -- write out the address as for the
- * principal entry, plus the current name as another A RR. Write the
- * reverse entry as pointing to the principal name.
- * 3 alias, no principal entry -- write a CNAME RR pointing to the primary.
- * 4 alias plus principal entry -- write an A RR with the primary's address.
- *
- * For example, suppose the /etc/hosts file has the following:
- * 129.215.64.48 baleshare baleshare-b agfahost
- * 29.215.160.155 baleshare-gw baleshare-a
- * Then baleshare is case 1, baleshare-gw is case 2, baleshare-a and
- * baleshare-b are case 4, and agfahost is case 3. Confused? BTW, changing
- * baleshare-gw to fred, say, would break the algorithm -- the main name of the
- * second interface better be related to the main name of the first!
- */
-
- void printhosts()
- { host *h, *m, *x;
- wire *w;
- FILE *f;
- int dotted;
-
- h = hostlist;
- while (h) {
- m = findPrincipal(h);
- if (h->IP) {
- if (m) {
- /* Case 2 */
- /* A RR for name */
- (void) fprintf(m->w->d->file,
- "%-23s IN\tA\t", h->name);
- printIP(m->w->d->file, h->IP);
- (void) putc('\n', m->w->d->file);
- if (m->w->d->MXdata) {
- (void) fputs(m->w->d->MXdata,
- m->w->d->file);
- }
- /* A RR for principal's name */
- (void) fprintf(m->w->d->file,
- "%-23s IN\tA\t", m->name);
- printIP(m->w->d->file, h->IP);
- (void) putc('\n', m->w->d->file);
- /* back-pointer -> principal */
- (void) fprintf(h->w->file,
- "%d\tIN\tPTR\t%s.%s.\n",
- h->IP & (~h->w->netmask),
- m->name, m->w->d->domainname);
- if (m->w->d->other) {
- (void) fprintf(m->w->d->other,
- "%-23s IN\tCNAME\t%s.%s.\n",
- h->name, m->name,
- m->w->d->domainname);
- }
- }
- else {
- /* Case 1 */
- dotted = (int) index(h->name, '.');
- if (!dotted) {
- (void) fprintf(h->w->d->file,
- "%-23s IN\tA\t", h->name);
- printIP(h->w->d->file, h->IP);
- (void) putc('\n', h->w->d->file);
- if (h->w->d->MXdata) {
- (void) fputs(h->w->d->MXdata,
- h->w->d->file);
- }
- if (h->w->d->other) {
- (void) fprintf(h->w->d->other,
- "%-23s IN\tCNAME\t%s.%s.\n",
- h->name, h->name,
- h->w->d->domainname);
- }
- }
- (void) fprintf(h->w->file,
- dotted ? "%d\tIN\tPTR\t%s\n"
- : "%d\tIN\tPTR\t%s.%s.\n",
- h->IP & (~h->w->netmask),
- h->name, h->w->d->domainname);
- }
- }
- else {
- if (m) {
- /* Case 4 */
- (void) fprintf(m->w->d->file,
- "%-23s IN\tA\t", h->name);
- printIP(m->w->d->file, h->primary->IP);
- (void) putc('\n', m->w->d->file);
- if (m->w->d->MXdata) {
- (void) fputs(m->w->d->MXdata,
- m->w->d->file);
- }
- if (m->w->d->other) {
- (void) fprintf(m->w->d->other,
- "%-23s IN\tCNAME\t%s.%s.\n",
- h->name, m->name,
- m->w->d->domainname);
- }
- }
- else {
- /* Case 3 */
- x = findPrincipal(h->primary);
- if (!x) x = h->primary;
- (void) fprintf(x->w->d->file,
- "%-23s IN\tCNAME\t%s.%s.\n",
- h->name, x->name,
- x->w->d->domainname);
- if (x->w->d->other) {
- (void) fprintf(x->w->d->other,
- "%-23s IN\tCNAME\t%s.%s.\n",
- h->name, x->name,
- x->w->d->domainname);
- }
- }
- }
- h = h->forward;
- }
- }
-
- static void readconfig()
- { FILE *config;
- long IP;
- char *ch;
- char buffer[LINEBUFFER];
- wire *w;
- domain *d;
-
- if ((config = fopen(CONFIG, "r")) == NULL) {
- (void) fprintf(stderr, "Failed to open %s\n", CONFIG);
- exit(1);
- }
- for (;;) {
- if ((ch = fgets(buffer, LINEBUFFER, config)) == NULL) break;
- while (isspace(*ch)) ch++;
- if (*ch == '\0' || *ch == '#') continue;
- IP = IPconvert(&ch);
- if (IP) {
- /* Wire record */
- w = wireTable + wires++;
- w->number = IP;
- w->netmask = IPconvert(&ch);
- w->RRfile = extractname(&ch);
- w->headerfile = extractname(&ch);
- w->domainname = extractname(&ch);
- w->file = stderr; /* meantime */
- w->d = findDomain(w->domainname);
- if (!w->d) {
- (void) fprintf(stderr, "Undefined domain %s:\n",
- w->domainname);
- (void) fputs(buffer, stderr);
- (void) fputc('\n', stderr);
- exit(2);
- }
- }
- else {
- /* Domain record */
- d = domainTable + domains++;
- d->domainname = extractname(&ch);
- d->RRfile = extractname(&ch);
- d->headerfile = extractname(&ch);
- d->otherZonefile = extractname(&ch);
- d->MXfile = extractname(&ch);
- d->file = stderr; /* meantime */
- d->other = NULL;
- d->MXdata = NULL;
- }
- }
- (void) fclose(config);
- }
-
- static void writeheader(f, h, MXdata)
- FILE *f;
- char *h;
- char *MXdata;
- { static struct passwd *pwd;
- time_t tt;
- static struct tm *ttm;
- static char *t;
- static char stamp[20];
- FILE *hf, *l;
- char buffer[LINEBUFFER];
-
- if (!pwd) {
- pwd = getpwuid(getuid());
- endpwent();
- tt = time(NULL);
- ttm = localtime(&tt);
- (void) sprintf(stamp, "%d%3.3d%3.3d",
- ttm->tm_year, ttm->tm_yday,
- ((60 * ttm->tm_hour) + ttm->tm_min) >> 1);
- t = asctime(ttm);
- if (l = fopen(LOG, "a")) {
- fprintf(l, "Generated by %s on %s", pwd->pw_name, t);
- fclose(l);
- }
- }
- (void) fprintf(f, ";; Generated by %s on %s\n", pwd->pw_name, t);
- if ((hf = fopen(h, "r")) == NULL) {
- (void) fprintf(stderr, "Can't open header file %s\n", h);
- exit(4);
- }
- (void) fprintf(f, ";; Including %s\n", h);
- for (;;) {
- if (fgets(buffer, LINEBUFFER, hf) == NULL) break;
- (void) fprintf(f, buffer, stamp);
- }
- (void) fclose(hf);
- (void) fprintf(f, ";; End of %s\n\n", h);
- if (MXdata) {
- (void) fputc('@', f);
- (void) fputs(MXdata, f);
- (void) fputc('\n', f);
- }
- }
-
- static void openfiles()
- { int i;
- int MXfd;
- int MXsize;
- wire *w;
- domain *d;
-
- for (i = 0, d = domainTable; i < domains; i++, d++) {
- if ((d->file = fopen(d->RRfile, "w")) == NULL) {
- (void) fprintf(stderr, "Can't open %s\n", d->RRfile);
- exit(3);
- }
- if (d->otherZonefile) {
- if ((d->other = fopen(d->otherZonefile, "w")) == NULL) {
- (void) fprintf(stderr, "Can't open %s\n",
- d->otherZonefile);
- exit(3);
- }
- }
- if (d->MXfile) {
- if ((MXfd = open(d->MXfile, O_RDONLY, 0)) < 0) {
- (void) fprintf(stderr, "Can't open %s\n",
- d->MXfile);
- exit(3);
- }
- d->MXdata = (char *) malloc(2048);
- if ((MXsize = read(MXfd, d->MXdata, 2048)) < 0) {
- (void) fprintf(stderr,
- "Couldn't read from %s\n",
- d->MXfile);
- exit(3);
- }
- (void) close(MXfd);
- *(d->MXdata + MXsize) = '\0';
- }
- writeheader(d->file, d->headerfile, d->MXdata);
- if (d->otherZonefile)
- writeheader(d->other, d->headerfile, d->MXdata);
- }
- for (i = 0, w = wireTable; i < wires; i++, w++) {
- if ((w->file = fopen(w->RRfile, "w")) == NULL) {
- exit(3);
- }
- writeheader(w->file, w->headerfile, (char *) 0);
- }
- }
-
- static void closefiles()
- { int i;
- domain *d;
- wire *w;
-
- for (i = 0, d = domainTable; i < domains; i++, d++) {
- (void) fclose(d->file);
- if (d->other) (void) fclose(d->other);
- }
- for (i = 0, w = wireTable; i < wires; i++, w++) {
- (void) fclose(w->file);
- }
- }
-